/*
根据用户输入的文件路径和后缀，搜索特定目录下的文件
判断输入的文件路径是否正确：正确输入、路径不存在（要求重输）、q（代表退出）、空字符（包括前面输入的空格、制表符，默设设置为当前路径）
判断输入的文件后缀是否正确：正确输入、q（代表退出）、空字符（包括前面输入的空格、制表符，默认设置为*）

FindFirstFile、FindNextFile、FindClose函数
GetCurrentDirectory函数
_tstat函数、stat.h库
自定义函数实现获取用户输入
_tcscmp函数、_tprintf函数
memset函数、fflush函数、getchar函数

无法处理这种形式的输入uv\ntxt\ndw\n
*/
#include <windows.h>
#include <tchar.h>
#include <sys/stat.h>
#include <stdio.h>

#define CONNECT "\\*."

int GetFilePath(PTSTR FilePath);
int GetFileExt(PTSTR FileBuffer);
int UserScanf(PTSTR FileBuffer);
void EnumerateFileInDrectory(PCTSTR FilePath);

int main(int argc, PCTSTR argv[])
{
    // 路径
    TCHAR FilePath[MAX_PATH] = {'\0'};
    // 文件后缀
    TCHAR FileExt[MAX_PATH] = {'\0'};

    // 获取用户输入的路径和文件后缀
    if (GetFilePath(FilePath) && GetFileExt(FileExt)) {
        _tprintf(TEXT("\n\n========================================\n"));
        _tprintf(TEXT("\t\t路径（去除前后的无效字符）：\"%s\"\n"), FilePath);
        _tprintf(TEXT("\t\t扩展名（去除前后的无效字符）：\"%s\"\n"), FileExt);
        _tcscat_s(FilePath, MAX_PATH, CONNECT);
        _tcscat_s(FilePath, MAX_PATH, FileExt);
        _tprintf(TEXT("\t\t组合的搜索字符串：%s\n"), FilePath);
        _tprintf(TEXT("========================================\n"));

        // 遍历目录下的文件
        EnumerateFileInDrectory(FilePath);
    }

    return 0;
}

/* 获取文件路径 */
int GetFilePath(PTSTR FilePath)
{
    _tprintf(TEXT("请输入要搜索的目录路径："));

    int iInputResult = UserScanf(FilePath);
    struct _tstat Buffer;

    // 路径不存在且不是"q"和空字符串
    while ((_tstat(FilePath, &Buffer)==-1) && (_tcscmp(FilePath, "q")!=0) && (iInputResult!=0)) {
        _tprintf(TEXT("你输入的文件路径\"%s\"有误，该路径无法找到。\n"), FilePath);
        _tprintf(TEXT("请输入要搜索的目录路径："));
        fflush(stdin);
        memset(FilePath, '\0', MAX_PATH);
        iInputResult = UserScanf(FilePath);
    }

    // 等于"q"
    if (_tcscmp(FilePath, "q")==0) {
        _tprintf(TEXT("你输入了\"%s\"，程序退出。\n"), FilePath);
        return 0;
    // 空字符串
    } else if (iInputResult==0) {
        _tprintf(TEXT("你的输入是空字符串。程序默认把文件路径设置为当前路径。\n"));
        if (GetCurrentDirectory(MAX_PATH, FilePath)==0) {
            _tprintf(TEXT("但获取当前目录的路径出错。程序退出。\n"));
            return 0; 
        }
    }

    return 1;
}

/* 获取文件后缀 */
int GetFileExt(PTSTR FileBuffer)
{
    _tprintf(TEXT("\n\n请输入要搜索的文件名后缀（无需办理入.号。输入*，表示所有文件；输入q，退出。）："));

    int iInputResult = UserScanf(FileBuffer);

    // 输入为空字符串（包括前面输入的空格、制表符）
    if (iInputResult==0) {
        *FileBuffer = '*';
        _tprintf(TEXT("你的输入是空字符串。程序默认把扩展名设置为*。\n"));
    } else if (_tcscmp(FileBuffer, "q")==0) {
        _tprintf(TEXT("你输入了\"%s\"，程序退出。\n"), FileBuffer);
        return 0;
    }

    return 1;
}

/* 构造自定义的输入函数 */
int UserScanf(PTSTR FileBuffer)
{
    // 理想状态下的输入：txt，返回值：1。
    // 特殊输入：q，返回值：1。
    // 特殊输入：  \ttxt\t  \t，去除前后的空字符，返回1。
    // 特殊输入：\n，返回值：0。
    // 特殊输入：  \t\n，返回值：0。
    char ch;

    // 清空输入缓冲区
    // 防止前面的文件路径误输入影响后面的后缀输入
    fflush(stdin);

    // 跳过输入缓冲区里前面的无效字符：空格、制表符
    while ((ch=getchar())=='\t' || (ch==' ')) {
        ;
    }

    // 排除诸如此类的无郊输入"   \t  \n"  
    if (ch=='\n') {
        return 0;
    }

    // 将输入缓冲区中间的有效字符写入FileBuffer字符数组
    while ((ch!=EOF) && (ch!='\n')) {
        *FileBuffer++ = ch;
        ch=getchar();
    }

    // 将指针后退1个单位
    FileBuffer -= 1;

    // 将FileBuffer字符数组最后面的空格、制表符填为\0
    // FileBuffer字符数组中间的空格、制表符不更改
    while ((ch=*FileBuffer)==' ' || (ch=='\t')) {
        *FileBuffer-- = '\0';
    }

    // 根据FileBuffer字符数组最后一个非零非制表符的字符，判断是否空字符
    if (*FileBuffer!='\0') {
        return 1;
    }

    return 0;
}

/* 遍历目录下的文件 */
void EnumerateFileInDrectory(PCTSTR FilePath)
{
    WIN32_FIND_DATA FindFileData;
    HANDLE hFile;

    hFile = FindFirstFile(FilePath, &FindFileData);

    if (hFile==INVALID_HANDLE_VALUE) {
        _tprintf(TEXT("查找文件失败，程序退出。\n"));
    } else {
        do {
            _tprintf(TEXT("\t\t%s\t\t"), FindFileData.cFileName);
            if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
                _tprintf(TEXT("加密"));
            }
            if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
                _tprintf(TEXT("隐藏"));
            }
            if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                _tprintf(TEXT("目录"));
            }
            _tprintf(TEXT("\n"));
        } while (FindNextFile(hFile, &FindFileData));
    }

    FindClose(hFile);
}